home *** CD-ROM | disk | FTP | other *** search
/ The 640 MEG Shareware Studio 2 / The 640 Meg Shareware Studio CD-ROM Volume II (Data Express)(1993).ISO / clang / jcool01.zip / ENVELOPE.H < prev    next >
C/C++ Source or Header  |  1992-10-01  |  18KB  |  451 lines

  1. // 
  2. // Copyright (C) 1992 General Electric Company.  
  3. // 
  4. // Permission is granted to any individual or institution to use, copy, modify, 
  5. // and distribute this software, provided that this complete copyright and 
  6. // permission notice is maintained, intact, in all copies and supporting
  7. // documentation.  
  8. // 
  9. // General Electric Company 
  10. // provides this software "as is" without express or implied warranty.  
  11. // 
  12. // Created: VDN 05/13/92 -- Initial design with ATT.
  13. // Updated: JAM 08/11/92 -- removed 'inline' from friend declarations
  14. // Updated: JAM 08/12/92 -- added 'inline' to shallow_swap definition
  15. //                          (probably just typo)
  16. // Updated: JAM 08/18/92 -- (optionally) made macros/CoolEnvelope into
  17. //                          a template instead of requiring user to
  18. //                          #define CoolLetter; made shallow_swap() static
  19. //                          and public (so operators not friends)
  20. // Updated: JAM 09/28/92 -- removed operator CoolLetter() conversions
  21. //                          since not necessary because publicly derived
  22. //                          
  23. //
  24. // This envelope is a generic template, has no data, publicly inherits
  25. // from the letter, and wraps outside a letter so that we can redefine 
  26. // the copy constructor to do a shallow copy instead of a deep copy,
  27. // when a return by value is required. 
  28. //
  29. // Such returns by value occur for example in: 
  30. // Matrix a, b, c; 
  31. // c = (a + b) + c; 
  32. // Note that the sum of a and b, (a+b), has to be deleted by the compiler,
  33. // and this requires (a+b) being returned by value. Return by value will
  34. // call the copy constructor of matrix, and so does a deep copy. 
  35. // There is one more copy at the assignment =. 
  36. // Note that the compiler generates temporary handles to the objects returned
  37. // by value and delete these objects when the current scope is exited.
  38. //
  39. // Arithmetic operations such as: +, -, *, /, %, and logical operations such 
  40. // as: |, &, ^ are overloaded to take envelopes, to avoid unecessary copying. 
  41. // Arithmetic, logical, shift operations are assumed non symmetric in general.
  42. //
  43. // Sometimes, the mutators +=, -=, ..., can be done without temporary memory,
  44. // such as matrix addition and negation, string concatenation, etc..
  45. // In these cases, use the flag ENVELOPE_* to generate versions of +, 
  46. // based on +=, etc... 
  47. #ifdef CoolLetter    // old way --Jam
  48. // Note that, the envelope is a macro rather than a parameterized
  49. // template, to allow expansion of member functions as needed.
  50. #endif
  51. //
  52. // This is an implementation of Coplien's envelope-letter idiom, 
  53. // that do not require reimplementation of the letter's member functions 
  54. // at the envelope level.
  55. // References: 
  56. // 1. Coplien (1992) Advanced C++ programming styles and idioms. 
  57. //    Addison-Wesley.
  58.  
  59.  
  60. #ifdef CoolLetter    // if old user
  61.  
  62. // Remember to include the letter class before this point.
  63. // #include <cool/CoolLetter.h>
  64.  
  65. class CoolEnvelope : public CoolLetter {    // Inherit all from class CoolLetter
  66. friend class CoolLetter;            
  67.  
  68. public:                        
  69.   inline CoolEnvelope();            // Empty Constructor
  70.   inline CoolEnvelope(CoolEnvelope&);        // Copy constructor
  71.   inline ~CoolEnvelope();            // Destructor
  72.  
  73.   inline operator CoolLetter& ();        // Conversion to letter
  74.   inline operator CoolLetter& () const;        
  75.  
  76.   friend ostream& operator<< (ostream&, const CoolEnvelope&); 
  77.   friend ostream& operator<< (ostream&, const CoolEnvelope*);
  78.  
  79.   // should be defined as member function of Letter class
  80.   // friend CoolLetter& operator= (CoolLetter&, CoolEnvelope&);
  81.  
  82.   // Defining operator + based on += with these macros, 
  83.   // if and only if += can be done in place, like += of matrices.
  84.  
  85. #define DECLARE_ENVELOPE_OPERATOR(op)                                      \
  86.   friend CoolEnvelope operator op (const CoolLetter&, const CoolLetter&); \
  87.   friend CoolEnvelope operator op (const CoolLetter&, const CoolEnvelope&);\
  88.   friend CoolEnvelope& operator op (CoolEnvelope&, const CoolLetter&);     \
  89.   friend CoolEnvelope& operator op (CoolEnvelope&, const CoolEnvelope&); 
  90.  
  91.   // Arithmetic operators
  92. #ifdef ENVELOPE_PLUS                // iff operator+= can be in place 
  93.   DECLARE_ENVELOPE_OPERATOR(+)
  94. #endif
  95. #ifdef ENVELOPE_MINUS                // iff operator-= can be in place 
  96.   DECLARE_ENVELOPE_OPERATOR(-)
  97. #endif
  98. #ifdef ENVELOPE_STAR                // iff operator*= can be in place 
  99.   DECLARE_ENVELOPE_OPERATOR(*)
  100. #endif
  101. #ifdef ENVELOPE_SLASH                // iff operator/= can be in place 
  102.   DECLARE_ENVELOPE_OPERATOR(/)
  103. #endif
  104. #ifdef ENVELOPE_PERCENT                // iff operator%= can be in place 
  105.   DECLARE_ENVELOPE_OPERATOR(%)
  106. #endif
  107.  
  108.   // Logical operators
  109. #ifdef ENVELOPE_VERTICAL                        // iff operator|= can be in place
  110.   DECLARE_ENVELOPE_OPERATOR(|)
  111. #endif
  112. #ifdef ENVELOPE_AMPERSAND            // iff operator&= can be in place
  113.   DECLARE_ENVELOPE_OPERATOR(&)
  114. #endif
  115. #ifdef ENVELOPE_CARET                // iff operator^= can be in place
  116.   DECLARE_ENVELOPE_OPERATOR(^)
  117. #endif
  118.  
  119.   // Shift operators
  120. #ifdef ENVELOPE_DOUBLE_LEFT_BRACKET        // iff operator<<= can be in place
  121.   DECLARE_ENVELOPE_OPERATOR(<<)    
  122. #endif
  123. #ifdef ENVELOPE_DOUBLE_RIGHT_BRACKET        // iff operator>>= can be in place
  124.   DECLARE_ENVELOPE_OPERATOR(>>)
  125. #endif
  126.  
  127. #undef DECLARE_ENVELOPE_OPERATOR        
  128.  
  129. protected:
  130.   inline void shallow_swap (CoolEnvelope*, CoolEnvelope*);
  131. };                        
  132.  
  133. // Envelope() -- Empty constructor creates an envelope wrapping an empty letter
  134. // Input:     none
  135. // Ouput:     envelope reference
  136.  
  137. inline CoolEnvelope::CoolEnvelope() 
  138. : CoolLetter()                    // create empty letter inside
  139. {}                        // nothing for envelope
  140.  
  141.  
  142. // Envelope() -- Copy constructor, swapping the contents of letter over.
  143. // Input:     envelope wraping a non null letter
  144. // Ouput:     envelope with contents of letter being swapped over.
  145.  
  146. inline CoolEnvelope::CoolEnvelope(CoolEnvelope& env) {
  147.   this->shallow_swap (this, &env);        // swap contents over
  148. }
  149.  
  150. // ~Envelope() -- Destructor, destroy letter too if non null.
  151. // Input:     none
  152. // Output:    none
  153.  
  154. inline CoolEnvelope::~CoolEnvelope() {}        // delete letter by inherit.
  155.  
  156.  
  157. // operator Letter&() -- Automatic conversion to letter, if necessary.
  158. // Input:     envelope reference
  159. // Ouput:     letter reference
  160.  
  161. inline CoolEnvelope::operator CoolLetter& () {
  162.   return *((CoolLetter*) this);            // same physical entity.
  163. }
  164.  
  165. inline CoolEnvelope::operator CoolLetter& () const {
  166.   return *((CoolLetter*) this);            // const version of above
  167. }
  168.  
  169.  
  170. // operator=  -- Assignment from a envelope back to real letter.
  171. //               Should be defined in CoolLetter class, not here.
  172. // Input:     envelope reference
  173. // Output:    letter reference with contents in envelope being swapped over
  174. // 
  175. // inline CoolLetter& operator= (CoolLetter& let, CoolEnvelope& env) {
  176. //   shallow_swap ((CoolEnvelope*) &let, &env);  // same physical layout
  177. //   return let;
  178. // }        
  179.  
  180. // shallow_swap() -- Swap contents by doing shallow copy of bytes.
  181. // Input:    pointer to two envelopes
  182. // Output:   none, contents of envelopes are swapped.
  183.  
  184. inline void CoolEnvelope::shallow_swap (CoolEnvelope* env1, CoolEnvelope* env2) {
  185.   int n = sizeof(CoolEnvelope);            // n = sizeof(CoolLetter)
  186.   char* temp = new char[n];            // temporary space for swap
  187.   char* env1_contents = (char*) env1;        // copy n bytes starting from ptr
  188.   char* env2_contents = (char*) env2;    
  189.   memcpy(temp, env1_contents, n);        // shallow swap the contents of
  190.   memcpy(env1_contents, env2_contents, n);    // env1 and env2
  191.   memcpy(env2_contents, temp, n);
  192.   delete [] temp;                // free temp space for swap
  193. }
  194.  
  195. // operator<<  -- Overload output operator to print envelope
  196. // Input:    os, envelope reference
  197. // Output:   os
  198.  
  199. inline ostream& operator<< (ostream& os, const CoolEnvelope& env) {
  200.   return os << *((CoolLetter*) &env);
  201. }
  202.  
  203. // operator<<  -- Overload output operator to print envelope
  204. // Input:    os, envelope pointer
  205. // Output:   os
  206.  
  207. inline ostream& operator<< (ostream& os, const CoolEnvelope* env) {
  208.   return os << *((CoolLetter*) env);
  209. }
  210.  
  211.  
  212. // operator op -- Use operator op_equal, and return an envelope by value
  213. //                so that deep copy of the object is avoided.
  214. //                For generality, operations are assumed non symmetric.
  215. // Input:    type reference, envelope reference, all 4 permutations.
  216. // Output:   envelope returned by value
  217.  
  218.  
  219. #define IMPLEMENT_ENVELOPE_OPERATOR(op,op_equal)                  \
  220. inline CoolEnvelope operator op (const CoolLetter& arg1, const CoolLetter& arg2) {\
  221.   CoolLetter temp(arg1);                    /*Deep copy of arg1*/         \
  222.   temp op_equal arg2;                /*Mutate with op arg2*/       \
  223.   CoolEnvelope& result = *((CoolEnvelope*) &temp);/*Same physical object*/    \
  224.   return result;                /*Copy envelope only*/          \
  225. }                                          \
  226.                                           \
  227. inline CoolEnvelope operator op (const CoolLetter& arg1, const CoolEnvelope& arg2){\
  228.   CoolLetter temp(arg1);                    /*Deep copy of arg1*/         \
  229.   temp op_equal *((CoolLetter*) &arg2);        /*Mutate with op arg2*/       \
  230.   CoolEnvelope& result = *((CoolEnvelope*) &temp);/*Same physical object*/    \
  231.   return result;                /*Copy envelope only*/          \
  232. }                                          \
  233.                                           \
  234. inline CoolEnvelope& operator op (CoolEnvelope& arg1, const CoolLetter& arg2) {\
  235.   CoolLetter& temp = *((CoolLetter*) &arg1);    /*Reuse arg1*/              \
  236.   temp op_equal arg2;                /*Mutate in place*/          \
  237.   return arg1;                    /*Envelope not copied*/          \
  238. }                                          \
  239.                                           \
  240. inline CoolEnvelope& operator op (CoolEnvelope& arg1, const CoolEnvelope& arg2) {\
  241.   CoolLetter& temp = *((CoolLetter*) &arg1);    /*Reuse arg1*/              \
  242.   temp op_equal *((CoolLetter*) &arg2);        /*Mutate in place*/          \
  243.   return arg1;                    /*Envelope not copied*/          \
  244. }                                          
  245.  
  246.   // Arithmetic operators:
  247. #ifdef ENVELOPE_PLUS                // iff operator+= can be in place
  248.   IMPLEMENT_ENVELOPE_OPERATOR(+,+=)
  249. #endif
  250.  
  251. #ifdef ENVELOPE_MINUS                // iff operator-= can be in place
  252.   IMPLEMENT_ENVELOPE_OPERATOR(-,-=)
  253. #endif
  254. #ifdef ENVELOPE_STAR                // iff operator*= can be in place
  255.   IMPLEMENT_ENVELOPE_OPERATOR(*,*=)
  256. #endif
  257. #ifdef ENVELOPE_SLASH                // iff operator/= can be in place
  258.   IMPLEMENT_ENVELOPE_OPERATOR(/,/=)
  259. #endif
  260. #ifdef ENVELOPE_PERCENT                // iff operator%= can be in place
  261.   IMPLEMENT_ENVELOPE_OPERATOR(%,%=)
  262. #endif
  263.  
  264.   // Logical operators:
  265. #ifdef ENVELOPE_VERTICAL            // iff operator|= can be in place
  266.   IMPLEMENT_ENVELOPE_OPERATOR(|,|=)
  267. #endif
  268. #ifdef ENVELOPE_AMPERSAND            // iff operator&= can be in place
  269.   IMPLEMENT_ENVELOPE_OPERATOR(&,&=)
  270. #endif
  271. #ifdef ENVELOPE_CARET                // iff operator^= can be in place
  272.   IMPLEMENT_ENVELOPE_OPERATOR(^,^=)
  273. #endif
  274.  
  275.   // Shift operators:
  276. #ifdef ENVELOPE_DOUBLE_LEFT_BRACKET        // iff operator<<= can be in place
  277.   IMPLEMENT_ENVELOPE_OPERATOR(<<,<<=)
  278. #endif
  279. #ifdef ENVELOPE_DOUBLE_RIGHT_BRACKET        // iff operator>>= can be in place
  280.   IMPLEMENT_ENVELOPE_OPERATOR(>>,>>=)
  281. #endif
  282.  
  283. #undef IMPLEMENT_ENVELOPE_OPERATOR        // Delete macro definition
  284.  
  285. #else    // new way: CoolEnvelope as class template
  286.  
  287. #ifndef CoolEnvelope_H
  288. #define CoolEnvelope_H
  289.  
  290. template<class CoolLetter>
  291. class CoolEnvelope : public CoolLetter {    // Inherit all from class CoolLetter
  292. friend class CoolLetter;            
  293.  
  294. public:                        
  295.   /*inline##*/ CoolEnvelope();            // Empty Constructor
  296.   /*inline##*/ CoolEnvelope(CoolEnvelope<CoolLetter>&);        // Copy constructor
  297.   /*inline##*/ ~CoolEnvelope();            // Destructor
  298.  
  299.   friend ostream& operator<< (ostream&, const CoolEnvelope&); 
  300.   friend ostream& operator<< (ostream&, const CoolEnvelope*);
  301.  
  302.   // should be defined as member function of Letter class
  303.   // friend CoolLetter& operator= (CoolLetter&, CoolEnvelope&);
  304.  
  305.   static inline void shallow_swap (CoolEnvelope*, CoolEnvelope*);
  306. protected:
  307. };
  308.  
  309. // Envelope() -- Empty constructor creates an envelope wrapping an empty letter
  310. // Input:     none
  311. // Ouput:     envelope reference
  312.  
  313. template<class CoolLetter>
  314. inline CoolEnvelope<CoolLetter>::CoolEnvelope() 
  315. : CoolLetter()                    // create empty letter inside
  316. {}                        // nothing for envelope
  317.  
  318.  
  319. // Envelope() -- Copy constructor, swapping the contents of letter over.
  320. // Input:     envelope wraping a non null letter
  321. // Ouput:     envelope with contents of letter being swapped over.
  322.  
  323. template<class CoolLetter>
  324. inline CoolEnvelope<CoolLetter>::CoolEnvelope(CoolEnvelope<CoolLetter>& env) {
  325.   this->shallow_swap (this, &env);        // swap contents over
  326. }
  327.  
  328. // ~Envelope() -- Destructor, destroy letter too if non null.
  329. // Input:     none
  330. // Output:    none
  331.  
  332. template<class CoolLetter>
  333. inline CoolEnvelope<CoolLetter>::~CoolEnvelope() {}        // delete letter by inherit.
  334.  
  335.  
  336. // operator=  -- Assignment from a envelope back to real letter.
  337. //               Should be defined in CoolLetter class, not here.
  338. // Input:     envelope reference
  339. // Output:    letter reference with contents in envelope being swapped over
  340. // 
  341. // inline CoolLetter& operator= (CoolLetter& let, CoolEnvelope& env) {
  342. //   shallow_swap ((CoolEnvelope*) &let, &env);  // same physical layout
  343. //   return let;
  344. // }        
  345.  
  346. // shallow_swap() -- Swap contents by doing shallow copy of bytes.
  347. // Input:    pointer to two envelopes
  348. // Output:   none, contents of envelopes are swapped.
  349.  
  350. template<class CoolLetter>
  351. inline void CoolEnvelope<CoolLetter>::shallow_swap (CoolEnvelope<CoolLetter>* env1, CoolEnvelope<CoolLetter>* env2) {
  352.   int n = sizeof(CoolEnvelope<CoolLetter>);            // n = sizeof(CoolLetter)
  353.   char* temp = new char[n];            // temporary space for swap
  354.   char* env1_contents = (char*) env1;        // copy n bytes starting from ptr
  355.   char* env2_contents = (char*) env2;    
  356.   memcpy(temp, env1_contents, n);        // shallow swap the contents of
  357.   memcpy(env1_contents, env2_contents, n);    // env1 and env2
  358.   memcpy(env2_contents, temp, n);
  359.   delete [] temp;                // free temp space for swap
  360. }
  361.  
  362. // operator<<  -- Overload output operator to print envelope
  363. // Input:    os, envelope reference
  364. // Output:   os
  365.  
  366. template<class CoolLetter>
  367. inline ostream& operator<< (ostream& os, const CoolEnvelope<CoolLetter>& env) {
  368.   return os << *((CoolLetter*) &env);
  369. }
  370.  
  371. // operator<<  -- Overload output operator to print envelope
  372. // Input:    os, envelope pointer
  373. // Output:   os
  374.  
  375. template<class CoolLetter>
  376. inline ostream& operator<< (ostream& os, const CoolEnvelope<CoolLetter>* env) {
  377.   return os << *((CoolLetter*) env);
  378. }
  379.  
  380. // operator op -- Use operator op_equal, and return an envelope by value
  381. //                so that deep copy of the object is avoided.
  382. //                For generality, operations are assumed non symmetric.
  383. // Input:    type reference, envelope reference, all 4 permutations.
  384. // Output:   envelope returned by value
  385.  
  386.  
  387. #define PASTE_(x,y) x##y
  388. #define PASTE(x,y) PASTE_(x,y)
  389. #define CoolEnvOp(name) PASTE(PASTE(CoolEnvelope,_),name)
  390. //## Should make 'name' a member func of CoolEnvelope instead, but
  391. // BC++ template bug expands out all member funcs even if never used
  392.  
  393. // Define for each operator OP that can be done in place:
  394. //inline CoolEnvelope<CoolLetter> operator OP (const CoolLetter&arg1, const CoolLetter&arg2)
  395. //   { return CoolEnvOp(NAME)(arg1, arg2); }
  396.  
  397. #define DEFINE_ENVELOPE_OPERATOR(name,op,op_equal)                  \
  398. template<class CoolLetter> \
  399. inline CoolEnvelope<CoolLetter> CoolEnvOp(name) (const CoolLetter& arg1, const CoolLetter& arg2) {\
  400.   CoolLetter temp(arg1);                    /*Deep copy of arg1*/         \
  401.   temp op_equal arg2;                /*Mutate with op arg2*/       \
  402.   CoolEnvelope<CoolLetter>& result = *((CoolEnvelope<CoolLetter>*) &temp);/*Same physical object*/    \
  403.   return result;                /*Copy envelope only*/          \
  404. }                                          \
  405.                                           \
  406. template<class CoolLetter> \
  407. inline CoolEnvelope<CoolLetter>& operator op (const CoolLetter& arg1, const CoolEnvelope<CoolLetter>& arg2) {\
  408.   CoolLetter temp(arg1);                    /*Deep copy of arg1*/         \
  409.   temp op_equal *((CoolLetter*) &arg2);        /*Mutate with op arg2*/       \
  410.   CoolEnvelope<CoolLetter>& result = *((CoolEnvelope<CoolLetter>*) &temp);/*Same physical object*/    \
  411.   return result;                /*Copy envelope only*/          \
  412. }                                          \
  413.                                           \
  414. template<class CoolLetter> \
  415. inline CoolEnvelope<CoolLetter>& operator op (CoolEnvelope<CoolLetter>& arg1, const CoolLetter& arg2) {\
  416.   CoolLetter& temp = *((CoolLetter*) &arg1);    /*Reuse arg1*/              \
  417.   temp op_equal arg2;                /*Mutate in place*/          \
  418.   return arg1;                    /*Envelope not copied*/          \
  419. }                                          \
  420.                                           \
  421. template<class CoolLetter> \
  422. inline CoolEnvelope<CoolLetter>& operator op (CoolEnvelope<CoolLetter>& arg1, const CoolEnvelope<CoolLetter>& arg2) {\
  423.   CoolLetter& temp = *((CoolLetter*) &arg1);    /*Reuse arg1*/              \
  424.   temp op_equal *((CoolLetter*) &arg2);        /*Mutate in place*/          \
  425.   return arg1;                    /*Envelope not copied*/          \
  426. } \
  427.  
  428.   // Arithmetic operators:
  429. DEFINE_ENVELOPE_OPERATOR(add,+,+=)
  430. DEFINE_ENVELOPE_OPERATOR(minus,-,-=)
  431. DEFINE_ENVELOPE_OPERATOR(star,*,*=)
  432. DEFINE_ENVELOPE_OPERATOR(slash,/,/=)
  433. DEFINE_ENVELOPE_OPERATOR(percent,%,%=)
  434.  
  435.   // Logical operators:
  436. DEFINE_ENVELOPE_OPERATOR(vertical,|,|=)
  437. DEFINE_ENVELOPE_OPERATOR(ampersand,&,&=)
  438. DEFINE_ENVELOPE_OPERATOR(caret,^,^=)
  439.  
  440.   // Shift operators:
  441. DEFINE_ENVELOPE_OPERATOR(double_left_bracket,<<,<<=)
  442. DEFINE_ENVELOPE_OPERATOR(double_right_bracket,>>,>>=)
  443.  
  444. #undef DEFINE_ENVELOPE_OPERATOR        // Delete macro definition
  445.  
  446.  
  447. #endif // CoolEnvelope_H
  448.  
  449. #endif // #ifdef CoolLetter
  450.  
  451.